package com.ecoolex.chinadutyfree.retailer.core.manager;

import java.time.Instant;
import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ecoolex.chinadutyfree.retailer.core.dao.CouponClassDAO;
import com.ecoolex.chinadutyfree.retailer.entity.CouponClass;
import com.ecoolex.chinadutyfree.retailer.entity.CouponClass.Column;
import com.ecoolex.chinadutyfree.retailer.entity.CouponClassExample;
import com.ecoolex.chinadutyfree.retailer.entity.CouponClassExample.Criteria;
import com.ecoolex.chinadutyfree.retailer.entity.CouponClassExpireStrategy;
import com.ecoolex.chinadutyfree.retailer.enums.CouponClassExpiryStrategy;
import com.ecoolex.chinadutyfree.retailer.enums.CouponClassProvideStrategy;
import com.ecoolex.chinadutyfree.retailer.enums.CouponClassStatus;
import com.ecoolex.chinadutyfree.retailer.enums.CouponClassType;
import com.ecoolex.chinadutyfree.retailer.enums.CouponClassUseLimit;
import com.ecoolex.chinadutyfree.retailer.pojo.EditCouponClassOneStep;
import com.ecoolex.chinadutyfree.retailer.pojo.EditCouponClassStep;
import com.ecoolex.chinadutyfree.retailer.pojo.EditCouponClassTwoStep;
import com.ecoolex.chinadutyfree.retailer.pojo.QueryCouponClassDTO;
import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.util.BeanUtil;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.framework.common.util.DateUtil;
import com.ecoolex.framework.common.util.StringUtil;

@Service
public class CouponClassManager {
	
    @Autowired
    private CouponClassDAO dao;
    
    @Autowired
    private CouponClassExpireStrategyManager couponClassExpireStrategyManager;
    
    @Autowired
    private CouponManager couponManager;
    
    public Pagination<CouponClass> queryCouponClass(QueryCouponClassDTO query, Page page) {
		CouponClassExample example = new CouponClassExample();
		Criteria criteria = example.createCriteria();
		if(Check.notNullOrTrimEmpty(query.getName())) {
			criteria.andNameLike("%"+query.getName()+"%");
		}
		if(Check.notNull(query.getProvideStrategy())) {
			criteria.andProvideStrategyEqualTo(query.getProvideStrategy());
		}
		if(Check.notNull(query.getUseLimit())) {
			criteria.andUseLimitEqualTo(query.getUseLimit());
		}
		if(Check.notNull(query.getStatus())) {
			criteria.andStatusEqualTo(query.getStatus());
		}
		if(Check.notNull(query.getType())) {
			criteria.andTypeEqualTo(query.getType());
		}
		criteria.andDeletedEqualTo(CouponClass.NOT_DELETED);
		example.setOffset(page.getFirstIndex());
		example.setRows(page.getPageSize());
		example.orderBy(Column.createTime.desc());
    	return Pagination.create(page, 
    		dao.countByExample(example),
    		() -> dao.selectByExample(example));
	}
    
    public Pagination<CouponClass> queryCouponClassForUser(Page page) {
    	CouponClassExample example = new CouponClassExample();
		Criteria criteria = example.createCriteria();
		Date now = new Date();
		criteria.andProvideStartTimeLessThanOrEqualTo(now)
				.andProvideEndTimeGreaterThanOrEqualTo(now)
				.andStatusEqualTo(CouponClassStatus.ONLINE.real())
				.andDeletedEqualTo(CouponClass.NOT_DELETED);
		example.setOffset(page.getFirstIndex());
		example.setRows(page.getPageSize());
		example.orderBy(Column.createTime.desc());
    	return Pagination.create(page, 
    		dao.countByExample(example),
    		() -> dao.selectByExample(example));
	}

	public CouponClass getCouponClassById(Integer couponClassId) {
		return dao.selectByPrimaryKeyWithLogicalDelete(couponClassId, CouponClass.NOT_DELETED);
	}

	public Boolean deleteCouponClass(CouponClass couponClass, String updateUser) {
		couponClass.setDeleted(CouponClass.IS_DELETED);
		couponClass.setUpdateUser(updateUser);
		couponClass.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(couponClass, Column.deleted,Column.updateUser,Column.updateTime);
		//删除所有用户的优惠券
		couponManager.deleteAllByCouponClassId(couponClass.getCouponClassId(), updateUser);
		return true;
	}

	public CouponClass updateCouponClassStep(EditCouponClassStep step, String updateUser){
		if(step instanceof EditCouponClassOneStep) {
			return editOne((EditCouponClassOneStep)step, updateUser);
		}else if(step instanceof EditCouponClassTwoStep) {
			return editTwo((EditCouponClassTwoStep)step, updateUser);
		}
		return null;
	}
	
	private CouponClass editOne(EditCouponClassOneStep edit,String updateUser) {
		//优惠券类型
		BizAssert.isTrue(Check.notNull(CouponClassType.FULL_REDUCTION.realOf(edit.getType())), 
			ResultCode.BIZ.build(1),
            "类型不存在");
		//满减券
		if(edit.getType().equals(CouponClassType.FULL_REDUCTION.real())) {
			BizAssert.isTrue(Check.notNullAndGtZero(edit.getThresholdPrice()), 
				ResultCode.BIZ.build(2),
	            "满减门槛金额不能为空");
			BizAssert.isTrue(Check.notNullAndGtZero(edit.getReducePrice()), 
				ResultCode.BIZ.build(3),
	            "满减金额不能为空");
			BizAssert.isTrue(Check.isGreatThanEqual(edit.getThresholdPrice(), edit.getReducePrice()), 
				ResultCode.BIZ.build(4),
	            "满减金额不能大于门槛金额");
		}
		//发放策略
		BizAssert.isTrue(Check.notNull(CouponClassProvideStrategy.LIMIT.realOf(edit.getProvideStrategy())),
			ResultCode.BIZ.build(5),
            "发放策略不存在");
		if (edit.getProvideStrategy().equals(CouponClassProvideStrategy.LIMIT.real())) {
            BizAssert.isTrue(
                Check.notNull(edit.getProvideNumber()) && Check.isRangeWithin(edit.getProvideNumber(), 1, 10000000),
                ResultCode.BIZ.build(6),
                "限制发放时需要填写发放数量; 范围1-10000000");
        }
		//使用限制（叠加/互斥）是否与流量渠道优惠券互斥
		BizAssert.isTrue(Check.notNull(CouponClassUseLimit.MUTEX.realOf(edit.getUseLimit())), 
			ResultCode.BIZ.build(7),
            "使用限制不存在");
		// 基本信息
        BizAssert.isTrue(Check.notNull(edit.getName()) && StringUtil.isIncludeTrimLength(edit.getName(), 1, 30),
            ResultCode.BIZ.build(8),
            "券标题须1-30个字符");
        BizAssert.isTrue(Check.notNull(edit.getDescription()) && StringUtil.isIncludeTrimLength(edit.getDescription(), 1, 200),
            ResultCode.BIZ.build(9),
            "优惠券使用说明须1-200个字符");
        // 发放时间
        BizAssert.isTrue(Check.notNull(edit.getProvideStartTime()), ResultCode.BIZ.build(10), "开始发放时间为空");
        BizAssert.isTrue(Check.notNull(edit.getProvideEndTime()), ResultCode.BIZ.build(10), "结束发放时间为空");
        DateUtil.cleanTimePart(edit.getProvideStartTime());
        DateUtil.setMaxTimePart(edit.getProvideEndTime());
        BizAssert.isTrue(Check.isLessThan(edit.getProvideStartTime(), edit.getProvideEndTime()),
            ResultCode.BIZ.build(14),
            "发放开始时间必须小于结束时间");
        BizAssert.isTrue(Check.isGreatThan(edit.getProvideEndTime(), Date.from(Instant.now())),
            ResultCode.BIZ.build(15),
            "发放结束时间必须大于当前时间");
        CouponClass couponClass = Check.notNullAndGtZero(edit.getCouponClassId()) ? getCouponClassById(edit.getCouponClassId())
            : null;

        if (Check.notNull(couponClass)) {
            // 修改
            BizAssert.isTrue(Check.notContains(couponClass.getStatus(),
                CouponClassStatus.ONLINE.real(),
                CouponClassStatus.INVALID.real()), ResultCode.BIZ.build(16), "上线,作废不能编辑");

            BeanUtil.copy(edit, couponClass);
            couponClass.setUpdateUser(updateUser);
            couponClass.setUpdateTime(Date.from(Instant.now()));
            dao.updateByPrimaryKeySelective(couponClass,
                Column.excludes(Column.status, Column.deleted, Column.createUser, Column.createTime));
        } else {
            // 创建
            couponClass = new CouponClass();
            BeanUtil.copy(edit, couponClass);
            couponClass.setReceiveNumber(0);
            couponClass.setUseNumber(0);
            couponClass.setStatus(CouponClassStatus.EDITING.real());
            couponClass.setDeleted(CouponClass.NOT_DELETED);
            couponClass.setCreateUser(updateUser);
            couponClass.setCreateTime(Date.from(Instant.now()));
            couponClass.setUpdateUser(updateUser);
            couponClass.setUpdateTime(Date.from(Instant.now()));
            dao.insert(couponClass);
        }
        checkEdited(couponClass);
        return couponClass;
	}
	
	private CouponClass editTwo(EditCouponClassTwoStep edit,String updateUser) {
		BizAssert.isTrue(Check.notNull(edit.getCouponClassId()), ResultCode.BIZ.build(17), "优惠券Id不存在");
        CouponClass couponClass = getCouponClassById(edit.getCouponClassId());
        BizAssert.isTrue(Check.notNull(couponClass), ResultCode.BIZ.build(18), "优惠券不存在");
        // 有效期策略
        BizAssert.isTrue(Check.notNull(CouponClassExpiryStrategy.ABSOLUTE_EXPIRY.realOf(edit.getExpiryStrategy())),
            ResultCode.BIZ.build(19),
            "优惠券有效期策略不存在");
        // 绝对有效期
        if (edit.getExpiryStrategy().equals(CouponClassExpiryStrategy.ABSOLUTE_EXPIRY.real())) {
            BizAssert.isTrue(Check.notNull(edit.getAbsoluteStartTime()), ResultCode.BIZ.build(20), "开始有效期为空");
            BizAssert.isTrue(Check.notNull(edit.getAbsoluteEndTime()), ResultCode.BIZ.build(21), "结束有效期为空");
            DateUtil.cleanTimePart(edit.getAbsoluteStartTime());
            DateUtil.setMaxTimePart(edit.getAbsoluteEndTime());
            BizAssert.isTrue(Check.isLessThan(edit.getAbsoluteStartTime(), edit.getAbsoluteEndTime()),
                ResultCode.BIZ.build(22),
                "开始有效期必须小于结束有效期");
            BizAssert.isTrue(Check.isGreatThan(edit.getAbsoluteEndTime(), Date.from(Instant.now())),
                ResultCode.BIZ.build(23),
                "结束有效期必须大于当前时间");
            BizAssert.isTrue(Check.isGreatThanEqual(edit.getAbsoluteEndTime(), couponClass.getProvideEndTime()),
                ResultCode.BIZ.build(24),
                "结束有效期必须大于或等于发放结束时间");
        } else if (edit.getExpiryStrategy().equals(CouponClassExpiryStrategy.RELATIVE_EXPIRY.real())) {
            BizAssert.throwBizException(ResultCode.BIZ.build(25), "不支持相对有效期");
        }

        CouponClassExpireStrategy expiryStrategy = couponClassExpireStrategyManager.getByCouponClassId(edit.getCouponClassId());
        if (Check.eq(edit.getExpiryStrategy(), CouponClassExpiryStrategy.ABSOLUTE_EXPIRY.real())) {
            DateUtil.cleanTimePart(edit.getAbsoluteStartTime());
            DateUtil.setMaxTimePart(edit.getAbsoluteEndTime());
        }
        if (Check.isNull(expiryStrategy)) {
            expiryStrategy = new CouponClassExpireStrategy();
            BeanUtil.copy(edit, expiryStrategy);
            couponClassExpireStrategyManager.create(expiryStrategy, updateUser);
        } else {
            BeanUtil.copy(edit, expiryStrategy);
            couponClassExpireStrategyManager.update(expiryStrategy, updateUser);
        }
        checkEdited(couponClass);
        return couponClass;
	}
	
	private void checkEdited(CouponClass couponClass) {
        // 检查是否完成
        if (CouponClassStatus.EDITING.real() == couponClass.getStatus()) {
        	CouponClassExpireStrategy expireStrategy = couponClassExpireStrategyManager.getByCouponClassId(couponClass.getCouponClassId());
            if (Check.notNull(expireStrategy)) {
                couponClass.setStatus(CouponClassStatus.EDITED.real());
                dao.updateByPrimaryKeySelective(couponClass, Column.status);
            }
        }
    }

	public Boolean onlineCouponClass(CouponClass couponClass, String updateUser) {
		couponClass.setStatus(CouponClassStatus.ONLINE.real());
		couponClass.setUpdateUser(updateUser);
		couponClass.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(couponClass, Column.status,Column.updateUser,Column.updateTime);
		return true;
	}

	public Boolean invalidCouponClass(CouponClass couponClass, String updateUser) {
		couponClass.setStatus(CouponClassStatus.INVALID.real());
		couponClass.setUpdateUser(updateUser);
		couponClass.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(couponClass, Column.status,Column.updateUser,Column.updateTime);
		return true;
	}

	public Boolean updateCouponClassProvideNumber(CouponClass couponClass, Integer newProvideNumber, String updateUser) {
		couponClass.setProvideNumber(newProvideNumber);
		couponClass.setUpdateUser(updateUser);
		couponClass.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(couponClass, Column.provideNumber,Column.updateUser,Column.updateTime);
		return true;
	}
	
	/**
	 * 用户领取优惠券更新状态
	 * @param couponClassId
	 * @param updaterUser
	 * @return
	 */
	public boolean addReceiveNumber(Integer couponClassId,String updateUser) {
		CouponClass couponClass = getCouponClassById(couponClassId);
		//不限量
		if(CouponClassProvideStrategy.UNLIMITED.equal(couponClass.getProvideStrategy())) {
			return dao.addReceiveNumber(couponClassId, updateUser)==1;
		}
		return dao.addReceiveNumberLimit(couponClassId, updateUser)==1;
	}
}